package com.gzhryc.system;

import com.gzhryc.common.ClassTools;
import com.gzhryc.common.StringTools;
import com.gzhryc.common.config.DefaultEnum;
import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.common.xml.XmlTools;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.JdbcSession;
import com.gzhryc.jdbc.MultiDBTools;
import com.gzhryc.system.dao.RoleDao;
import com.gzhryc.system.dao.RoleMenuDao;
import com.gzhryc.system.dao.db.Menu;
import com.gzhryc.system.dao.db.Role;
import com.gzhryc.system.dao.db.RoleMenu;
import com.gzhryc.system.dao.enums.MenuEnum;
import com.gzhryc.system.dto.RoleConfig;
import com.gzhryc.system.dto.RoleSearch;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class RoleService {

	static Logger log = Logger.getLogger(RoleService.class);

	public static RoleService self() {
		return MultiDBTools.getService(RoleService.class, true);
	}

	public static RoleService self(String jdbcKey) {
		return MultiDBTools.getService(jdbcKey, RoleService.class, true);
	}

	RoleDao roleDao;
	RoleMenuDao roleMenuDao;

	public RoleService(String jdbcKey) {
		this.roleDao = new RoleDao(jdbcKey);
		this.roleMenuDao = new RoleMenuDao(jdbcKey);
	}

	public List<Role> findBySearch(RoleSearch search, Integer pageNo, Integer pageLimit) {
		Conditions condition = new Conditions(Role.class);
		condition.and().likeBoth("name", search.name);
		condition.and().likeBoth("code", search.code);
		condition.and().is("status", search.status);
		try {
			return roleDao.findByCondition(condition, pageNo, pageLimit);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	public Long countBySearch(RoleSearch search) {
		Conditions condition = new Conditions(Role.class);
		condition.and().likeBoth("name", search.name);
		condition.and().likeBoth("code", search.code);
		condition.and().is("status", search.status);
		try {
			return roleDao.count(condition);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return 0L;
	}

	public List<Role> findAll() {
		try {
			return roleDao.findAll();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	public List<Role> findByIds(String ids) {
		if(StringTools.isNotBlank(ids)) {
			List<Long> roleIds = StringTools.split2Long(ids, ",");
			return findByIds(roleIds);
		}
		return null;
	}

	public List<Role> findByIds(List<Long> roleIds) {
		if(roleIds != null && roleIds.size() > 0) {
			Conditions conditions = new Conditions(Role.class);
			conditions.and().in("id", roleIds);
			try {
				return roleDao.findByCondition(conditions);
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	public List<Role> findByCodes(String codes) {
		Conditions conditions = new Conditions(Role.class);
		String[] temp = codes.split(",");
		conditions.and().in("code", temp);
		try {
			return roleDao.findByCondition(conditions);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	public Role getByNameOrCode(String name, String code) {
		Conditions condition = new Conditions(Role.class);
		condition.and().is("name", name).or().is("code", code);
		try {
			return roleDao.get(condition);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	public Role getByCode(String code) {
		Conditions condition = new Conditions(Role.class);
		condition.and().is("code", code);
		try {
			return roleDao.get(condition);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	public Role getByName(String name) {
		Conditions condition = new Conditions(Role.class);
		condition.and().is("name", name);
		try {
			return roleDao.get(condition);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 新增角色
	 * 
	 * @param role
	 * @return
	 * @throws LogicException
	 */
	public synchronized boolean add(Role role) throws LogicException {
		Role temp = getByNameOrCode(role.getName(), role.getCode());
		if (temp != null) {
			throw new LogicException("角色名称或代码已存在");
		}
		if (role.getStatus() == null) {
			role.setStatus(DefaultEnum.Status.Usable.index()); // 默认启用
		}
		role.setCreateDate(new Date());
		try {
			if (roleDao.insert(role) > 0) {
				return true;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 修改角色信息
	 * 
	 * @param role
	 * @return
	 * @throws LogicException
	 */
	public synchronized boolean update(Role role) throws LogicException {
		Role temp = getByCode(role.getCode());
		if (temp != null && !temp.getId().equals(role.getId())) {
			throw new LogicException("角色代码已存在");
		}
		temp = getByName(role.getName());
		if (temp != null && !temp.getId().equals(role.getId())) {
			throw new LogicException("角色名称已存在");
		}
		if (temp == null) {
			temp = getById(role.getId());
		}
		temp.setName(role.getName());
		temp.setCode(role.getCode());
		temp.setNote(role.getNote());
		try {
			if (roleDao.updateNotNull(temp) > 0) {
				return true;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}

	public Role getById(Long id) {
		try {
			return roleDao.getById(id);
		} catch (SQLException e) {
			e.printStackTrace();
		}

		return null;
	}

	public boolean deleteById(Long id) {
		try {
			if (roleDao.deleteById(id) > 0) {
				return true;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 获取指定管理员德所有角色
	 * 
	 * @param managerId
	 * @return
	 */
	public List<Role> findByManagerId(Long managerId) {
		try {
			return roleDao.findByManagerId(managerId);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}


	//===== 角色与菜单关系 =====//

	public List<RoleMenu> findByRoleId(Long roleId) {
		if(roleId != null) {
			Conditions conditions = new Conditions(RoleMenu.class);
			conditions.and().is("roleId",roleId);
			try {
				return roleMenuDao.findByCondition(conditions);
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	public RoleMenu getRoleMenu(Long roleId, Long menuId) {
		Conditions condition = new Conditions(RoleMenu.class);
		condition.and().is("roleId", roleId);
		condition.and().is("menuId", menuId);
		try {
			return roleMenuDao.get(condition);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	public synchronized boolean addRoleMenu(Long roleId, Long menuId) {
		if (roleId != null && menuId != null) {
			RoleMenu temp = getRoleMenu(roleId, menuId);
			if (temp == null) {
				temp = new RoleMenu();
				temp.setMenuId(menuId);
				temp.setRoleId(roleId);
				JdbcSession.begin();
				try {
					if (roleMenuDao.insert(temp) > 0) {
						// 关联权限
						List<Menu> menuList = MenuService.self(roleDao.getJdbcKey()).findByParentAndType(temp.getMenuId(),
								MenuEnum.Type.FunAuthorization.index());
						if (menuList != null && menuList.size() > 0) {
							for (Menu menu : menuList) {
								temp = new RoleMenu();
								temp.setMenuId(menu.getId());
								temp.setRoleId(roleId);
								temp.setCreateDate(new Date());
								roleMenuDao.insert(temp);
							}
						}
						JdbcSession.commit();
						return true;
					}
				} catch (SQLException e) {
					e.printStackTrace();
					JdbcSession.rollback();
				} finally {
					JdbcSession.end();
				}
			}
		}
		return false;
	}

	public boolean readRoleConfig(InputStream inStream) {
		if (inStream != null) {
			RoleConfig config = XmlTools.changToObject(inStream, RoleConfig.class, false);
			if (config != null) {
				if (config.getRoles() != null && config.getRoles().size() > 0) {
					List<Menu> menuList = MenuService.self().findAll();
					for (RoleConfig.Item item : config.getRoles()) {
						//如果角色没有配置菜单，则默认不初始化
						if (item.getMenus() != null && item.getMenus().size() > 0) {
							//整理新配置
							List<RoleMenu> newRoleMenuList = new ArrayList<>();
							for (RoleConfig.Menu menu : item.getMenus()) {
								if (StringUtils.isNotBlank(menu.getLink()) || StringUtils.isNotBlank(menu.getPermission())) {
									Menu entity = null;
									if (menuList != null && menuList.size() > 0) {
										for (Menu temp : menuList) {
											if (StringUtils.isNotBlank(menu.getLink()) && menu.getLink().equals(temp.getLink())) {
												entity = temp;
												break;
											}
											if (StringUtils.isNotBlank(menu.getPermission()) && menu.getPermission().equals(temp.getPermission())) {
												entity = temp;
												break;
											}
										}
									}

									if (entity != null) {
										//存在该菜单
										RoleMenu temp = new RoleMenu();
										temp.setMenuId(entity.getId());
										temp.setCreateDate(new Date());
										newRoleMenuList.add(temp);
									}
								}
							}

							if (newRoleMenuList.size() > 0) {
								//如果角色没有配置菜单，则默认不添加
								Role role = getByCode(item.getCode());
								if (role == null) {
									role = ClassTools.copy(new Role(), item);
									try {
										if (!add(role)) {
											continue;
										}
									} catch (LogicException e) {
										log.error(e.getMessage(), e);
										continue;
									}
								}

								//获取旧的配置
								List<RoleMenu> roleMenuList = this.findByRoleId(role.getId());

								for (RoleMenu roleMenu : newRoleMenuList) {
									boolean toAdd = true;
									if (roleMenuList != null && roleMenuList.size() > 0) {
										for (int i = 0; i < roleMenuList.size(); i++) {
											RoleMenu oldRoleMenu = roleMenuList.get(i);
											if (oldRoleMenu.getMenuId().equals(roleMenu.getMenuId())) {
												toAdd = false;
												roleMenuList.remove(i);
												break;
											}
										}
									}

									if (toAdd) {
										roleMenu.setRoleId(role.getId());
										try {
											roleMenuDao.insert(roleMenu);
										} catch (SQLException e) {
											log.error(e.getMessage(), e);
										}
									}
								}

								if (roleMenuList != null && roleMenuList.size() > 0) {
									for (RoleMenu roleMenu : roleMenuList) {
										log.info("删除{{0}}角色配置的菜单{{1}}", roleMenu.getRoleId(), roleMenu.getMenuId());
										try {
											roleMenuDao.deleteById(roleMenu.getId());
										} catch (SQLException e) {
											log.error(e.getMessage(),e);
										}
									}
								}
							}else{
								log.error("{{0}}角色中配置菜单都没有相应菜单信息", item.getCode());
							}
						} else {
							log.error("{{0}}角色中未配置菜单", item.getCode());
						}
					}
					return true;
				}
			}
		}
		return false;
	}

	public boolean readRoleConfig(String filePath) {
		File file = new File(filePath);
		InputStream inStream = null;
		if (file.exists()) {
			try {
				inStream = new FileInputStream(file);
				return readRoleConfig(inStream);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
		return false;
	}

	/**
	 * 修改角色的菜单权限
	 * 
	 * @param roleId
	 * @param data
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public boolean editMenu(Long roleId, List<Map<String, Object>> data) {
		Conditions condition = new Conditions(RoleMenu.class);
		condition.and().is("roleId", roleId);
		JdbcSession.begin();
		try {
			roleMenuDao.deleteByCondition(condition);
			if (data != null) {
				for (Map<String, Object> item : data) {
					RoleMenu temp = new RoleMenu();
					temp.setMenuId(Long.valueOf(item.get("id").toString()));
					temp.setRoleId(roleId);
					temp.setCreateDate(new Date());
					roleMenuDao.insert(temp);
					// 关联权限
					List<Menu> menuList = MenuService.self(roleDao.getJdbcKey()).findByParentAndType(temp.getMenuId(),
							MenuEnum.Type.FunAuthorization.index());
					if (menuList != null && menuList.size() > 0) {
						for (Menu menu : menuList) {
							temp = new RoleMenu();
							temp.setMenuId(menu.getId());
							temp.setRoleId(roleId);
							temp.setCreateDate(new Date());
							roleMenuDao.insert(temp);
						}
					}
					List<Map<String, Object>> children = (List<Map<String, Object>>) item.get("children");
					editChildMenu(roleId, children);
				}
				JdbcSession.commit();
			}
			return true;
		} catch (SQLException e) {
			e.printStackTrace();
			JdbcSession.rollback();
		} finally {
			JdbcSession.end();
		}
		return false;
	}

	@SuppressWarnings("unchecked")
	private void editChildMenu(Long roleId, List<Map<String, Object>> data) {
		try {
			if (data != null) {
				for (Map<String, Object> item : data) {
					RoleMenu temp = new RoleMenu();
					temp.setMenuId(Long.valueOf(item.get("id").toString()));
					temp.setRoleId(roleId);
					temp.setCreateDate(new Date());
					roleMenuDao.insert(temp);
					// 关联权限
					List<Menu> menuList = MenuService.self(roleDao.getJdbcKey()).findByParentAndType(temp.getMenuId(),
							MenuEnum.Type.FunAuthorization.index());
					if (menuList != null && menuList.size() > 0) {
						for (Menu menu : menuList) {
							temp = new RoleMenu();
							temp.setMenuId(menu.getId());
							temp.setRoleId(roleId);
							temp.setCreateDate(new Date());
							roleMenuDao.insert(temp);
						}
					}
					List<Map<String, Object>> children = (List<Map<String, Object>>) item.get("children");
					editChildMenu(roleId, children);
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public boolean delByMenuId(Long menuId) {
		if (menuId != null) {
			Conditions conditions = new Conditions(RoleMenu.class);
			conditions.and().is("menuId", menuId);
			try {
				return roleMenuDao.deleteByCondition(conditions) >= 0;
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return false;
	}

}
